package android_serialport_api;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import android.util.Log;
/**
 * 串口通信类，提供对Android设备串口的打开、关闭和数据读写功能
 *
 * 该类通过JNI调用底层串口驱动实现，包含以下主要功能：
 * 1. 检查并修改串口设备文件权限
 * 2. 打开/关闭串口设备
 * 3. 获取输入输出流进行数据读写
 */
public class SerialPort {

	private static final String TAG = "SerialPort";

	/*
	 * Do not remove or rename the field mFd: it is used by native method close();
	 */
	private FileDescriptor mFd;
	private FileInputStream mFileInputStream;
	private FileOutputStream mFileOutputStream;


	/**
	 * 串口构造函数
	 *
	 * @param device   要打开的串口设备文件对象
	 * @param baudrate 波特率设置（如9600, 115200等）
	 * @param flags    附加标志位（参考底层open函数说明）
	 * @throws SecurityException 当无法获取串口设备读写权限时抛出
	 * @throws IOException       当打开设备失败时抛出
	 *
	 * 执行流程：
	 * 1. 检查设备文件读写权限，必要时通过root权限修改权限
	 * 2. 调用native方法打开串口设备
	 * 3. 创建关联的输入输出流
	 */

	public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException {

		/* Check access permission */
		/* 权限检查与处理块：
		   当设备文件缺少读写权限时，尝试通过su命令修改权限为666 */
		if (!device.canRead() || !device.canWrite()) {
			try {
				/* Missing read/write permission, trying to chmod the file */
				Process su;
				su = Runtime.getRuntime().exec("/system/xbin/su");
				String cmd = "chmod 666 " + device.getAbsolutePath() + "\n"
						+ "exit\n";
				su.getOutputStream().write(cmd.getBytes());
				if ((su.waitFor() != 0) || !device.canRead()
						|| !device.canWrite()) {
					throw new SecurityException();
				}
			} catch (Exception e) {
				e.printStackTrace();
				throw new SecurityException();
			}
		}
		// 调用JNI方法打开设备文件
		mFd = open(device.getAbsolutePath(), baudrate, flags);
		if (mFd == null) {
			Log.e(TAG, "native open returns null");
			throw new IOException();
		}
		mFileInputStream = new FileInputStream(mFd);
		mFileOutputStream = new FileOutputStream(mFd);
	}

	// Getters and setters

	/**
	 * 获取串口输入流
	 * @return 用于读取串口数据的输入流对象
	 */
	public InputStream getInputStream() {
		return mFileInputStream;
	}
	/**
	 * 获取串口输出流
	 * @return 用于写入串口数据的输出流对象
	 */
	public OutputStream getOutputStream() {
		return mFileOutputStream;
	}

	// JNI
	/**
	 * 本地方法 - 打开串口设备
	 * @param path     设备文件绝对路径（如"/dev/ttyS1"）
	 * @param baudrate 波特率设置
	 * @param flags    打开标志位（如O_RDWR等）
	 * @return 设备文件描述符，打开失败返回null
	 */
	private native static FileDescriptor open(String path, int baudrate, int flags);

	/**
	 * 本地方法 - 关闭串口设备
	 * 会同时关闭关联的输入输出流
	 */
	public native void close();

	// 类初始化时加载JNI库
	static {
		System.loadLibrary("serial_port");
	}
}
